package com.stottlerhenke.simbionic.editor;

import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;

import com.stottlerhenke.simbionic.common.parser.SB_Parser;
import com.stottlerhenke.simbionic.editor.gui.ComponentRegistry;
import com.stottlerhenke.simbionic.editor.gui.SB_Autocomplete;
import com.stottlerhenke.simbionic.editor.gui.SB_BreakpointFrame;
import com.stottlerhenke.simbionic.editor.gui.SB_Catalog;
import com.stottlerhenke.simbionic.editor.gui.SB_Condition;
import com.stottlerhenke.simbionic.editor.gui.SB_Descriptors;
import com.stottlerhenke.simbionic.editor.gui.SB_Drawable;
import com.stottlerhenke.simbionic.editor.gui.SB_Element;
import com.stottlerhenke.simbionic.editor.gui.SB_LocalsTree;
import com.stottlerhenke.simbionic.editor.gui.SB_Output;
import com.stottlerhenke.simbionic.editor.gui.SB_ProjectBar;
import com.stottlerhenke.simbionic.editor.gui.SB_Rectangle;
import com.stottlerhenke.simbionic.editor.gui.SB_ToolBar;
import com.stottlerhenke.simbionic.editor.gui.api.EditorRegistry;
import com.stottlerhenke.simbionic.editor.parser.SB_ParserEditorInterface;

/**
 * SimBionic is the SimBionic editor main panel, and can also be
 * run as a standalone application. 
 * 
 * Note: cannot run more than one instance of
 * editor now since parser is singleton.
 */
public class SimBionicEditor
{   
    public static final String NEW_COMMAND = "New";
    public static final String NEW_COMMAND_TOOLTIP = "Create a new SimBionic project...";
    public static final String OPEN_COMMAND = "Open...";
    public static final String OPEN_COMMAND_TOOLTIP = "Open a SimBionic project...";
    public static final String SAVE_COMMAND = "Save";
    public static final String SAVEAS_COMMAND = "Save As...";

    public static final String EXPORTHEADER_COMMAND = "Export C++ Header...";
    public static final String EXPORTJAVA_COMMAND = "Export Java Class...";
    public static final String IMPORTXML_COMMAND = "Import XML...";
    public static final String EXPORTXML_COMMAND = "Export XML...";

    public static final String RELOADBASE_COMMAND = "Reload base.dat";

    public static final String EXIT_COMMAND = "Exit";
    public static final String EXIT_COMMAND_TOOLTIP = "Exit SimBionic...";

    public static final String BUILD_COMMAND = "Build";
    public static final String COMPILE_COMMAND = "Compile";

    public static final String EDIT_COMMAND = "Edit";
    public static final String UNDO_COMMAND = "Undo";
    public static final String REDO_COMMAND = "Redo";
    public static final String CUT_COMMAND = "Cut";
    public static final String COPY_COMMAND = "Copy";
    public static final String PASTE_COMMAND = "Paste";
    public static final String DELETE_COMMAND = "Delete";
    public static final String SELECTALL_COMMAND = "Select All";
    public static final String FIND_COMMAND = "Find";
    public static final String REPLACE_COMMAND = "Replace";
    public static final String FINDREPLACE_COMMAND = "Find and Replace...";
    public static final String VIEW_COMMAND = "View";
    public static final String BACK_COMMAND = "Go Back";
    public static final String FORWARD_COMMAND = "Go Forward";
    public static final String PREVERROR_COMMAND = "Previous Error";
    public static final String NEXTERROR_COMMAND = "Next Error";

    public static final boolean DEV = true;

    public static final String BUILD_MENU = "Build";
    public static final String COMPILE_ITEM = "Compile";
    public static final String SETTINGS_ITEM = "Project Settings...";
    public static final String EDIT_MENU = "Edit";
    public static final String UNDO_ITEM = "Undo";
    public static final String REDO_ITEM = "Redo";
    public static final String CUT_ITEM = "Cut";
    public static final String COPY_ITEM = "Copy";
    public static final String PASTE_ITEM = "Paste";
    public static final String DELETE_ITEM = "Delete";
    public static final String FIND_REPLACE_ITEM = "Find and Replace...";
    public static final String VIEW_MENU = "View";
    public static final String BACK_ITEM = "Go Back";
    public static final String FORWARD_ITEM = "Go Forward";
    public static final String PREV_ERROR_ITEM = "Previous Error";
    public static final String NEXT_ERROR_ITEM = "Next Error";
    protected static int _count = 0;

    public SB_ToolBar toolbar; 
    protected SB_ProjectBar _projectBar;
    protected EditorRegistry _editorRegistry;

    protected boolean _debugMode = false;
    
    /**
     * Allows for editing and displaying of breakpoints.
     */
    public SB_BreakpointFrame _breakpointFrame = new SB_BreakpointFrame();
    
    protected String _name = "unnamed";

    /** Whether or not this editor is visible. */
    protected boolean _visible = true;

    /** Whether this editor's content has been modified since the last save. */
    protected boolean _dirty = false;

    /**
     * This variable describes whether the SimBionic editor is in standalone
     * mode or running as part of another application. This controls things like
     * whether it initializes its own menu or uses another application menu.
     */
    public static boolean standalone = false;

    public Vector _recentList;
    protected static final int _maxRecent = 4;
    protected JMenuItem[] _recentItems;

    protected SB_Catalog mCatalog;
    protected SB_Descriptors mDescriptors;

    public Action newAction;
    public Action openAction;
    public Action saveAction;
    public Action saveAsAction;
    public Action exitAction;

    public Action exportJavaAction;
    public Action exportHeaderAction;
    public Action exportXMLAction;
    public Action importXMLAction;

    public Action undoAction;
    public Action redoAction;
    public Action cutAction, deleteAction;
    public Action copyAction;
    public Action pasteAction;
    public Action findAction, replaceAction, selectAllAction;

    public Action nextErrorAction;
    public Action prevErrorAction;
    public Action startAction, stopAction, pauseAction;
    public Action stepIntoAction, stepOverAction, stepOneTickAction, runToFinalAction;
    public Action showCurrentAction, connectAction, runAction, breakpointAction;
    public Action showBreakpointsAction;
    public Action compileAction, settingsAction;

    protected Rectangle _bounds;
    protected boolean _maximized;

    public SimBionicEditor()
    {
        super();
        _name = "SimBionic";
        FileManager.initialize(this);

        initializeSharedActions();

        // note: cannot run more than one instance of editor now since by
        // default parsing uses the parser singleton stored in
        // parserEditorInterface.
        SB_EditorDataInterface idface = new SB_EditorDataInterface();
        SB_ParserEditorInterface iface = new SB_ParserEditorInterface(idface);
        SB_ParserEditorInterface.setParser(new SB_Parser(iface, null));
   
    }

    protected SB_ProjectBar createProjectBar()
    {
        return new SB_ProjectBar(this);
    }

    public SB_LocalsTree createLocalsTree()
    {
        return new SB_LocalsTree(this);
    }

    public SB_Output createOutput()
    {
        return new SB_Output(this);
    }

    public SB_Autocomplete createAutocomplete()
    {
        return new SB_Autocomplete(10, this);
    }

    /**
     * SB_AbstractAction is a tiny class that just exists so you dont have to keep
     * typing putValue over and over. If you use AbstractAction instead, don't
     * forget to putValue(Action.ACTION_COMMAND_KEY, COMMAND).
     */
    abstract class SB_AbstractAction extends AbstractAction
    {
        public SB_AbstractAction(String name)
        {
            this(name, null, null, null, null, null);
        }

        public SB_AbstractAction(String name, Icon icon)
        {
            this(name, icon, null, null, null, null);
        }

        public SB_AbstractAction(String name, Icon icon, String description)
        {
            this(name, icon, description, null, null, null);
        }

        public SB_AbstractAction(String name, Icon icon, String description, KeyStroke accelerator,
                Integer mnemonic)
        {
            this(name, icon, description, accelerator, null, mnemonic);
        }

        public SB_AbstractAction(String name, Icon icon, String description, KeyStroke accelerator)
        {
            this(name, icon, description, accelerator, null, null);
        }

        public SB_AbstractAction(String name, Icon icon, String description, KeyStroke accelerator,
                String command, Integer mnemonic)
        {
            super(name, icon);
            if (command == null)
                putValue(Action.ACTION_COMMAND_KEY, name);
            else
                putValue(Action.ACTION_COMMAND_KEY, command);
            if (description != null)
                putValue(Action.SHORT_DESCRIPTION, description);
            if (accelerator != null)
                putValue(Action.ACCELERATOR_KEY, accelerator);
            if (mnemonic != null)
                putValue(Action.MNEMONIC_KEY, mnemonic);
        }
    }

    /**
     * Initialize the actions that are shared between the standalone and
     * embedded versions of SimBionic. <br>

     */
    public void initializeSharedActions()
    {
    	settingsAction = new SB_AbstractAction(SETTINGS_ITEM, null)
    	{
    		public void actionPerformed(ActionEvent e)
    		{
    			ComponentRegistry.getProjectBar().actionPerformed(e);
    		}
    	};

    	newAction = new SB_AbstractAction(NEW_COMMAND, Util.getImageIcon("New16.gif"), "New", KeyStroke
    			.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK, false), new Integer(KeyEvent.VK_N))
    	{
    		public void actionPerformed(ActionEvent e)
    		{
    			ComponentRegistry.getProjectBar().newProject();
    		}
    	};

        openAction = new SB_AbstractAction(OPEN_COMMAND, Util.getImageIcon("Open16.gif"), "Open", KeyStroke
                .getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_MASK, false), new Integer(KeyEvent.VK_O))
        {
            public void actionPerformed(ActionEvent e)
            {
                if (!saveIfModified())
                    return;
                ComponentRegistry.getProjectBar().openProject();
            }
        };

        saveAction = new SB_AbstractAction(SAVE_COMMAND, Util.getImageIcon("Save16.gif"),"Save",KeyStroke
            .getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK, false), new Integer(KeyEvent.VK_N))
        {
            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getProjectBar().saveProject();
            }
        };
        saveAction.setEnabled(true);

        saveAsAction = new SB_AbstractAction(SAVEAS_COMMAND, Util.getImageIcon("SaveAs16.gif"),"Save As",null,
            new Integer(KeyEvent.VK_A))
        {
            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getProjectBar().saveProjectAs();
            }
        };
        saveAsAction.setEnabled(true);

        exportJavaAction = new SB_AbstractAction(SimBionicEditor.EXPORTJAVA_COMMAND,null,"Export Java Class",null,
            new Integer(KeyEvent.VK_J))
        {
            public void actionPerformed(ActionEvent e)
            {
                FileManager.getInstance().exportClass();
            }
        };
        exportJavaAction.setEnabled(true);

        exportHeaderAction = new SB_AbstractAction(SimBionicEditor.EXPORTHEADER_COMMAND,null,"Export C++ Header",null,
            new Integer(KeyEvent.VK_C))
        {
            public void actionPerformed(ActionEvent e)
            {
                FileManager.getInstance().exportHeader();
            }
        };
        exportHeaderAction.setEnabled(true);

        exportXMLAction = new SB_AbstractAction(SimBionicEditor.EXPORTXML_COMMAND,null,"Export to XML",null,
            new Integer(KeyEvent.VK_X))
        {
            public void actionPerformed(ActionEvent e)
            {
                FileManager.getInstance().exportXML();
            }
        };
        exportXMLAction.setEnabled(true);

        importXMLAction = new SB_AbstractAction(SimBionicEditor.IMPORTXML_COMMAND, null,"Import from XML",null, 
            new Integer(KeyEvent.VK_I))
        {
            public void actionPerformed(ActionEvent e)
            {
                FileManager.getInstance().importXML();
            }
        };
        importXMLAction.setEnabled(true);

        exitAction = new SB_AbstractAction(EXIT_COMMAND,null,"Exit",KeyStroke.getKeyStroke(KeyEvent.VK_X,
            InputEvent.CTRL_MASK, false),new Integer(KeyEvent.VK_X))
        {
            public void actionPerformed(ActionEvent event)
            {
                // FIXME : this should try to save if modified first
                System.exit(0);
            }
        };

  
        undoAction = new SB_AbstractAction("Undo", Util.getImageIcon("Undo16.gif"),"Undo",KeyStroke.getKeyStroke(KeyEvent.VK_Z,
            InputEvent.CTRL_MASK, false),new Integer(KeyEvent.VK_U))
        {
            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getContent().undo();
            }
        };


        redoAction = new SB_AbstractAction("Redo", Util.getImageIcon("Redo16.gif"),"Redo",KeyStroke.getKeyStroke(KeyEvent.VK_Y,
            InputEvent.CTRL_MASK, false), new Integer(KeyEvent.VK_R))
        {

            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getContent().redo();
            }
        };

        findAction = new SB_AbstractAction("Find", Util.getImageIcon("Find16.gif"), "Find",KeyStroke.getKeyStroke(KeyEvent.VK_F,
            InputEvent.CTRL_MASK, false),new Integer(KeyEvent.VK_F))
        {
            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getContent().showFindDialog();
            }
        };

        replaceAction = new SB_AbstractAction("Replace", null,"Replace",KeyStroke.getKeyStroke(KeyEvent.VK_H,
            InputEvent.CTRL_MASK, false),new Integer(KeyEvent.VK_R))
        {
            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getContent().showReplaceDialog();
            }
        };

        selectAllAction = new SB_AbstractAction("Select All", null, "Select All", KeyStroke.getKeyStroke(KeyEvent.VK_A,
            InputEvent.CTRL_MASK, false),new Integer(KeyEvent.VK_A))
        {
            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getContent().selectAll();
            }
        };

        cutAction = new SB_AbstractAction("Cut", Util.getImageIcon("Cut16.gif"),"Cut",KeyStroke.getKeyStroke(KeyEvent.VK_X,
            InputEvent.CTRL_MASK, false),new Integer(KeyEvent.VK_T))
        {

            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getContent().canvasCut();
            }
        };

        deleteAction = new SB_AbstractAction("Delete",Util.getImageIcon("Delete16.gif"),"Delete",KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,
            0, false),new Integer(KeyEvent.VK_D))
        {

            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getContent().canvasDelete();
            }
        };

        copyAction = new SB_AbstractAction("Copy", Util.getImageIcon("Copy16.gif"),"Copy",KeyStroke.getKeyStroke(KeyEvent.VK_C,
            InputEvent.CTRL_MASK, false),new Integer(KeyEvent.VK_C))
        {

            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getContent().canvasCopy();
            }
        };

        pasteAction = new SB_AbstractAction("Paste", Util.getImageIcon("Paste16.gif"),"Paste",KeyStroke.getKeyStroke(KeyEvent.VK_V,
            InputEvent.CTRL_MASK, false),new Integer(KeyEvent.VK_P))
        {

            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getContent().canvasPaste(e);
            }
        };

        prevErrorAction = new SB_AbstractAction("Prev Error")
        {

            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getProjectBar().goToPreviousError();
            }
        };
        prevErrorAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_UP,
            InputEvent.ALT_DOWN_MASK, false));
        prevErrorAction.setEnabled(false);

        nextErrorAction = new SB_AbstractAction("Next Error")
        {

            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getProjectBar().goToNextError();
            }
        };
        nextErrorAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,
            InputEvent.ALT_DOWN_MASK, false));
        nextErrorAction.setEnabled(false);

        compileAction = new SB_AbstractAction(COMPILE_COMMAND, Util.getImageIcon("Compile.gif"), "Compile",KeyStroke.getKeyStroke(KeyEvent.VK_F7, 0,
            false),new Integer(KeyEvent.VK_C))
        {
            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getProjectBar().compileSIM();
            }
        };

        connectAction = new SB_AbstractAction("Connect", Util.getImageIcon("Connect.gif"))
        {
            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getProjectBar().connectDebug();
            }
        };
        connectAction.putValue(Action.SHORT_DESCRIPTION, "Connect");

        runAction = new SB_AbstractAction("Quick-Run", Util.getImageIcon("Run.gif"))
        {
            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getProjectBar().actionPerformed(e);
            }
        };
        runAction.putValue(Action.SHORT_DESCRIPTION, "Quick-Run (Ctrl+F5)");
        runAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F5,
            InputEvent.CTRL_MASK, false));
        // TODO remove this when implemented
        runAction.setEnabled(false);

        breakpointAction = new SB_AbstractAction("Breakpoint", Util.getImageIcon("Breakpoint.gif"))
        {
            public void actionPerformed(ActionEvent e)
            {
                SB_Drawable drawable = ComponentRegistry.getContent().getActiveCanvas()._selDrawable;
                if(drawable instanceof SB_Rectangle || drawable instanceof SB_Condition){
                	((SB_Element)drawable)._isBreakpoint = !((SB_Element)drawable)._isBreakpoint;
                	ComponentRegistry.getContent().repaint();
                	int nodeId = ((SB_Element)drawable).getId();
                	String behName = ComponentRegistry.getContent().getBehavior()._name;
                	if(((SB_Element)drawable)._isBreakpoint){
                		SB_Breakpoint breakpoint = _breakpointFrame.addBreakpoint();
                		breakpoint._elem = (SB_Element)drawable;
                		if(drawable instanceof SB_Rectangle){breakpoint._type = SB_Breakpoint.RECTANGLE;}
                		else{breakpoint._type = SB_Breakpoint.CONDITION;}
                		breakpoint._behavior = behName;
                		breakpoint._enabled = true;
                		breakpoint._entityId = SB_Breakpoint.ALL_ENTITIES;
                		breakpoint._elemId = nodeId;
                		breakpoint._constraint = "";
                		breakpoint._varName = ((SB_Element)drawable)._expr;
                		if(_debugMode){
                			_projectBar.addBreakElemDebug(breakpoint);
                		}
                	}
                	else{
                		SB_Breakpoint breakpoint = _breakpointFrame.removeElemBreakpoint(behName, nodeId);
                		if(_debugMode){
                			_projectBar.removeBreakpointDebug(breakpoint);
                		}
                	}
                }
                else{
                	Toolkit.getDefaultToolkit().beep();
                }
            }
        };
        breakpointAction.setEnabled(true);
        breakpointAction.putValue(Action.SHORT_DESCRIPTION, "Breakpoint (F9)");
        breakpointAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F9, 0,
            false));

        showBreakpointsAction = new SB_AbstractAction("Breakpoint List", Util.getImageIcon("BreakpointsList.gif"))
        {
            public void actionPerformed(ActionEvent e)
            {
            	_breakpointFrame.setVisible(true);
            }
        };
        showBreakpointsAction.setEnabled(true);
        showBreakpointsAction.putValue(Action.SHORT_DESCRIPTION, "Breakpoint List");
        
        startAction = new SB_AbstractAction("Start", Util.getImageIcon("Start.gif"))
        {
            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getProjectBar().startDebug();
            }
        };
        startAction.setEnabled(true);
        startAction.putValue(Action.SHORT_DESCRIPTION, "Start (F5)");
        startAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0,
            false));

        stopAction = new SB_AbstractAction("Stop", Util.getImageIcon("Stop.gif"))
        {
            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getProjectBar().stopDebug();
            }
        };
        stopAction.putValue(Action.SHORT_DESCRIPTION, "Stop (Shift+F5)");
        stopAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F5,
            InputEvent.SHIFT_MASK, false));

        pauseAction = new SB_AbstractAction("Pause", Util.getImageIcon("Pause.gif"))
        {
            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getProjectBar().pauseDebug();
            }
        };
        pauseAction.setEnabled(false);
        pauseAction.putValue(Action.SHORT_DESCRIPTION, "Pause (F6)");
        pauseAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F6, 0,
            false));

        stepIntoAction = new SB_AbstractAction("Step Into", Util.getImageIcon("StepInto.gif"))
        {
            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getProjectBar().stepIntoDebug();
            }
        };
        stepIntoAction.putValue(Action.SHORT_DESCRIPTION, "Step Into (F11)");
        stepIntoAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F11, 0,
            false));

        stepOverAction = new SB_AbstractAction("Step Over", Util.getImageIcon("StepOver.gif"))
        {
            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getProjectBar().stepOverDebug();
            }
        };
        stepOverAction.setEnabled(false);
        stepOverAction.putValue(Action.SHORT_DESCRIPTION, "Step Over (F10)");
        stepOverAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F10, 0,
            false));

        stepOneTickAction = new SB_AbstractAction("Step One Tick", Util.getImageIcon("StepOneTick.gif"))
        {
            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getProjectBar().stepOneTickDebug();
            }
        };
        stepOneTickAction.setEnabled(false);
        stepOneTickAction.putValue(Action.SHORT_DESCRIPTION, "Step One Tick (Shift+F10)");
        stepOneTickAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F10,
            InputEvent.SHIFT_MASK, false));

        runToFinalAction = new SB_AbstractAction("Run To Final", Util.getImageIcon("RunToFinal.gif"))
        {
            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getProjectBar().runToFinal();
            }
        };
        runToFinalAction.putValue(Action.SHORT_DESCRIPTION, "Run To Final (Shift+F11)");
        runToFinalAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F11,
            InputEvent.SHIFT_MASK, false));

        showCurrentAction = new SB_AbstractAction("Show Current", Util.getImageIcon("ShowCurrent.gif"))
        {
            public void actionPerformed(ActionEvent e)
            {
                ComponentRegistry.getProjectBar()._debugger.showCurrentRectangle();
            }
        };
        showCurrentAction.setEnabled(true);
        showCurrentAction.putValue(Action.SHORT_DESCRIPTION, "Show Current");
    }
    
    /**
     * TODO: Call this method on startup to load the recent file list
     * TODO: Replace with existing library to read/write configuration information
     * 
     * @param fileMenu
     */
    protected void loadRecentList(JMenu fileMenu)
    {
        File file = new File("prefs.dat");
        
        if (file.exists())
        {
            try
            {
                FileInputStream in = new FileInputStream(file);
                ObjectInputStream s = new ObjectInputStream(in);
                try
                {
                    _recentList = (Vector) s.readObject();
                    _bounds = (Rectangle) s.readObject();
                    _maximized = s.readBoolean();
                } catch (ClassNotFoundException e)
                {
                    System.err.println("class not found");
                    e.printStackTrace();
                }
                in.close();
            } catch (FileNotFoundException e)
            {
                System.err.println("file not found");
            } catch (IOException e)
            {
                System.err.println("i/o exception");
            }
        }
        if (_recentList == null)
            _recentList = new Vector();
        int size = _recentList.size();
        for (int i = size - 1; i >= 0; --i)
        {
            file = (File) _recentList.get(i);

        }

        fileMenu.add(new JPopupMenu.Separator());
        _recentItems = new JMenuItem[_maxRecent];
        for (int i = 0; i < _maxRecent; ++i)
        {
            JMenuItem recentItem = new JMenuItem();
            recentItem.addActionListener(ComponentRegistry.getProjectBar());
            fileMenu.add(recentItem);
            _recentItems[i] = recentItem;
        }
        updateRecentItems();
    }

    public void updateRecentItems()
    {
        if (_recentList == null)
            return;
        int size = _recentList.size();
        if (size > _maxRecent)
            _recentList.setSize(_maxRecent);

        for (int i = 0; i < _maxRecent; ++i)
        {
            JMenuItem recentItem = _recentItems[i];
            if (i < size)
            {
                File file = (File) _recentList.get(i);

                recentItem.setText((i + 1) + "  " + file.getName());
                recentItem.setToolTipText(file.getAbsolutePath());
                recentItem.setVisible(true);
            } else
                recentItem.setVisible(false);
        }
    }

    public void addRecentProject(File f)
    {
    	if(_recentList != null)
    		_recentList.add(f);
        updateRecentItems();
    }

    /**
     * TODO: Call this method to save the recent file list
     */
    public void saveRecentList()
    {
        updateRecentItems();
        File file = new File("prefs.dat");
        
        try
        {
            FileOutputStream out = new FileOutputStream(file);
            ObjectOutputStream s = new ObjectOutputStream(out);
            s.writeObject(_recentList);
            JFrame frame = ComponentRegistry.getFrame();

            boolean maximized = (frame.getExtendedState() & JFrame.MAXIMIZED_BOTH) != 0;
            if (maximized)
            {
                frame.setVisible(false);
                frame.setExtendedState(JFrame.NORMAL);
                frame.setVisible(true);
            }
            s.writeObject(frame.getBounds());
            s.writeBoolean(maximized);
            s.flush();
            out.close();
        } catch (IOException exeption)
        {
            System.err.println("i/o exception");
        }
    }

    /**
     * Disables appropriate toolbar items that should not be available
     * when using debugger.
     * 
     * @param _debugger
     */
    public void setDebugModeOn(){
    	_debugMode = true;
    	undoAction.setEnabled(false);
        redoAction.setEnabled(false);
        cutAction.setEnabled(false);
        deleteAction.setEnabled(false);
        pasteAction.setEnabled(false);
        
        stepOneTickAction.setEnabled(false);
       	runToFinalAction.setEnabled(false);
        
        newAction.setEnabled(false);
        openAction.setEnabled(false);
        importXMLAction.setEnabled(false);
        saveAsAction.setEnabled(false);
        
    }
    
    /**
     * Reenables appropriate toolbar items upon leaving debug mode.
     *
     */
    public void setDebugModeOff(){
    	_debugMode = false;
    	newAction.setEnabled(true);
        openAction.setEnabled(true);
        importXMLAction.setEnabled(true);
        saveAsAction.setEnabled(true);
    }
    
    public void requestContentFocus()
    {
        (ComponentRegistry.getContent()).getActiveCanvas().requestFocus();
    }

    public SB_Catalog getCatalog()
    {
        return (ComponentRegistry.getProjectBar())._catalog;
    }
    
    public boolean isDirty()
    {
        return isModified();
    }

    public boolean isModified()
    {
        SB_ProjectBar projectBar = ComponentRegistry.getProjectBar();
        SB_Catalog catalog = projectBar._catalog;
        return projectBar.isAPDModified() || projectBar.isSBPModified() || catalog.isBTNModified();
    }

    public boolean saveIfModified()
    {
        return (ComponentRegistry.getProjectBar()).saveIfModified();
    }

    public void setActive(boolean active)
    {
        if (active)
        {
            ComponentRegistry.getContent().requestFocus();
        } else
        {
            ComponentRegistry.getToolBar().hideDialogs();
        }
    }

    public boolean saveContent(File pBaseFilename)
    {
        ComponentRegistry.getProjectBar().setSBPFile(pBaseFilename);
        return ComponentRegistry.getProjectBar().saveProject();
    }

    public boolean loadContent(File pBaseFilename)
    {
        // TODO This stuff should be moved to the file manager
        return ComponentRegistry.getProjectBar().loadProject(pBaseFilename);
    }

    /**
     * @return Returns the project bar.
     */
    public SB_ProjectBar getProjectBar()
    {
        return _projectBar;
    }

    /**
     * @param bar the current project bar for the editor
     */
    public void setProjectBar(SB_ProjectBar bar)
    {
        _projectBar = bar;
    }

    /**
     * 
     * @return the custom editor registry for the editor
     */
    public EditorRegistry getEditorRegistry() {
    	if (_editorRegistry == null)
    		_editorRegistry = new EditorRegistry();
    	return _editorRegistry;
    }
    
    /**
     * set the custom editor registry for the editor
     * @param registry
     */
    public void setEditorRegistry(EditorRegistry registry) {
    	_editorRegistry = registry;
    }

    /**
     * Sets the dirty flag for the current project.
     * @param dirty the new value for the flag
     */
    public void setDirty(boolean dirty)
    {
        saveAction.setEnabled(dirty);
    }
}